home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
pt20pc.zip
/
UNDOREDO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-04
|
8KB
|
287 lines
#include "pt.h"
void pascal
/* XTAG:initChanges */
initChanges()
{
extern struct changeItem *change;
extern struct changeItem scrapBuffer;
extern int tailChange, nextChange;
register int i;
for(i = 0; i < NHISTORY; i++) {
change[i].type = CNULL;
change[i].firstPiece = NULL;
}
tailChange = nextChange = 0;
scrapBuffer.firstPiece = getFreePiece();
scrapBuffer.firstPiece->file = ADDFILE;
scrapBuffer.firstPiece->position = 0L;
scrapBuffer.firstPiece->length = 0L;
}
void pascal
/* XTAG:IncrementNextChange */
IncrementNextChange()
{
extern int tailChange, nextChange;
extern struct changeItem *change;
/* change history is a circular buffer */
if( ++nextChange >= NHISTORY )
nextChange = 0;
/* is the change buffer full? */
if( nextChange == tailChange ) {
/* if so, free the 'tailChange' change */
if( change[tailChange].type != CNULL )
freePieces( change[tailChange].firstPiece );
change[tailChange].firstPiece = NULL;
/* and move the 'tail' up one */
if( ++tailChange >= NHISTORY )
tailChange = 0;
}
}
void pascal
/* XTAG:redo */
redo()
{
extern unsigned char msgBuffer[];
extern struct window *selWindow;
extern long selBegin, selEnd;
extern struct changeItem *change;
extern int tailChange, nextChange;
extern struct openFile *files;
extern unsigned char *userMessages[];
register struct changeItem *newChange;
struct changeItem *thisChange, *prevChange;
int n, type, count;
/* check if this is a readOnly file */
if( files[selWindow->fileId].readOnly ) {
sprintf(msgBuffer, userMessages[READONLYFILE],
files[selWindow->fileId].origName);
msg(msgBuffer, 1);
return;
}
if( nextChange == tailChange ) {
noChanges:
msg("No previous change to redo", 2);
return;
}
n = nextChange; /* remember where the next change is */
/* find the change to redo (not a delete ) */
count = 0;
while( 1 ) {
thisChange = &change[n];
if((thisChange->type)!=CDELETE && (thisChange->type)!=CNULL)
break;
if( --n < 0 )
n = NHISTORY - 1;
if( count++ > NHISTORY )
goto noChanges;
}
switch( thisChange->type ) {
case CINSERT:
type = CINSERT;
goto doCopy;
case CCOPY:
case CMOVE:
type = CCOPY;
doCopy:
/* see if the previous change was a delete */
if( --n < 0 )
n = NHISTORY - 1;
prevChange = &change[n];
if( thisChange->position == prevChange->position
&& prevChange->type == CDELETE )
/* the delete must go into the history first */
deleteChars(selWindow->fileId, NOUPDATE, 0);
/* find the slot to record this change */
IncrementNextChange();
/* record the change before copyPieces changes things */
newChange = &change[nextChange];
newChange->type = type;
newChange->position = selBegin;
newChange->length = thisChange->length;
newChange->fileId = selWindow->fileId;
newChange->firstPiece = dupPieces(thisChange->firstPiece);
copyPieces(thisChange->firstPiece, selWindow, selBegin,
thisChange->length, 1);
break;
case CDELETE:
deleteChars(selWindow->fileId, UPDATEWINDOWS, 0);
break;
}
}
void pascal
/* XTAG:undo */
undo(doHistory)
int doHistory;
{
extern unsigned char msgBuffer[];
extern struct window *selWindow;
extern long selBegin, selEnd;
extern struct window *windowList;
extern struct changeItem *change;
extern int tailChange, nextChange;
extern int debug;
int n, delAlso, count;
register struct changeItem *newChange;
struct changeItem *thisChange, *prevChange;
struct window *w1;
if( nextChange == tailChange ) {
noChanges:
msg("No previous change to undo", 2);
return;
}
/* find the change to undo */
n = nextChange;
count = 0;
while( 1 ) {
thisChange = &change[n];
if( (thisChange->type) != CNULL )
break;
if( --n < 0 )
n = NHISTORY - 1;
if( count++ > NHISTORY )
goto noChanges;
}
nextChange = n;
if( --n < 0 )
n = NHISTORY - 1;
prevChange = &change[n];
/* find a window displaying the file the change was made in */
if( thisChange->fileId != selWindow->fileId ) {
w1 = windowList;
while( w1 != NULL && w1->fileId != thisChange->fileId )
w1 = w1->nextWindow;
if( w1 == NULL ) {
msg("Cannot undo. No windows have that file open.",3);
return;
} else
selWindow = w1;
}
switch( thisChange->type ) {
case CDELETE:
if( doHistory ) {
/* find the slot to record this change */
IncrementNextChange();
newChange = &change[nextChange];
newChange->type = CCOPY;
newChange->position = thisChange->position;
newChange->length = thisChange->length;
newChange->fileId = selWindow->fileId;
newChange->firstPiece =
dupPieces(thisChange->firstPiece);
}
showChange();
copyPieces(thisChange->firstPiece, selWindow,
thisChange->position, thisChange->length, 1);
if( !doHistory ) {
change[nextChange--].type = CNULL;
if( nextChange < 0 )
nextChange = NHISTORY - 1;
}
/* see if this is really the DELETE of a CMOVE */
if( prevChange->type != CMOVE )
break;
if( doHistory ) /* if we are recording in history */
newChange->type = CMOVE; /* change it to a move */
/* else finish undoing the move by dropping through */
/* to the CCOPY case to delete the MOVEd text */
thisChange = prevChange;
/* erase this change from the history list */
case CCOPY:
selBegin = thisChange->position;
selEnd = selBegin + thisChange->length - 1;
showChange();
deleteChars(thisChange->fileId, UPDATEWINDOWS,
doHistory ? 0 : 2);
/* erase this change from the history list */
if( !doHistory ) {
change[nextChange--].type = CNULL;
if( nextChange < 0 )
nextChange = NHISTORY - 1;
}
break;
case CINSERT:
/* delete the characters inserted */
selBegin = thisChange->position;
selEnd = selBegin + thisChange->length - 1;
/* test this first so we can avoid updating the */
/* screen twice once for the delete and again for */
/* the copy to follow */
if( thisChange->position == prevChange->position
&& prevChange->type == CDELETE )
delAlso = NOUPDATE;
else
delAlso = UPDATEWINDOWS;
showChange();
deleteChars(thisChange->fileId, delAlso,
doHistory ? 0 : 2);
/* erase this change from the history list */
if( !doHistory ) {
/* erase the last 1 or 2 changes */
change[nextChange--].type = CNULL;
if( delAlso == NOUPDATE ) {
change[nextChange--].type = CNULL;
}
if( nextChange < 0 )
nextChange = NHISTORY - 1;
}
/* see if there is a previous, related delete to undo */
if( delAlso == NOUPDATE ) {
if( doHistory ) {
/* find the slot to record this change */
IncrementNextChange();
newChange = &change[nextChange];
newChange->type = CINSERT;
newChange->position = selBegin;
newChange->length = prevChange->length;
newChange->fileId = prevChange->fileId;
newChange->firstPiece =
dupPieces(prevChange->firstPiece);
}
copyPieces(prevChange->firstPiece, selWindow,
selBegin, prevChange->length, 1);
}
break;
}
}
/* make sure the change is visible */
void pascal
/* XTAG:showChange */
showChange()
{
extern long selBegin, selEnd;
extern struct window *selWindow;
extern struct window *windowList;
/* if the selection window is not on top */
/* or if the selection is not in the window */
/* then move the window to show the selection */
if( windowList != selWindow || selBegin < selWindow->posTopline
|| selEnd > selWindow->posBotline )
doGoSel(selWindow);
}